<?php
namespace app\common\controller;
require_once __DIR__.'/../../../vendor/autoload.php';

use Exception;
use think\facade\Log;

use WeChatPay\Builder;
use WeChatPay\Crypto\AesGcm;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Formatter;
use WeChatPay\Util\PemUtil;

/**
 * 微信支付封装类
 */
class WeiXinpay
{
    /**
     * 微信支付配置参数
     */
    // 商户号
    private static $merchantId = '1624381272';
    // 「商户API证书」的「证书序列号」
    private static $merchantSerialNumber = '6FFCB2DCDFD27B7E1E2BF7D4AD697A3E56DCB123';
    private static $merchantPrivateKey;
    private static $platformCertificateSerial;
    private static $api_v3_key = '3ce6a6ca72e3d9567d8cc7339cbf8124';
    private static $platformPublicKeyInstance;
    private static $appid = 'wx5f1a667410b75bdf';
    /**
     * 初始化配置
     */
    private static function initConfig()
    {
        self::$merchantPrivateKey = Rsa::from('file://'.__DIR__.'/../../../public/pay/weixin/apiclient_key.pem',Rsa::KEY_TYPE_PRIVATE);
        // 从本地文件中加载「商户API私钥」，「商户API私钥」会用来生成请求的签名

        // 从本地文件中加载「微信支付平台证书」(可使用证书下载工具得到），用来验证微信支付应答的签名
        $platformCertificateFilePath = 'file://'.__DIR__.'/../../../public/pay/weixin/wechatpay_66E8A6D2EFDA0A28506EFA638239B3C454F2BD1E.pem';
        self::$platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);
        // 从「微信支付平台证书」中获取「证书序列号」
        self::$platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateFilePath);
    }

    /**
     * 微信H5支付
     * @param array $params 支付参数
     * @return array
     */
    public static function wapPay($params, $notify_url,$device = 'Wap')
    {
        try {
            // 初始化配置
            self::initConfig();
            // 初始化客户端
            $array = [
                'mchid'      => self::$merchantId,
                'serial'     => self::$merchantSerialNumber,
                'privateKey' => self::$merchantPrivateKey,
                'certs'      => [
                    self::$platformCertificateSerial => self::$platformPublicKeyInstance,
                ],
            ];
            $instance = Builder::factory($array);
            // 以 Native 支付为例，发送请求
            $resp = $instance
                ->chain('v3/pay/transactions/h5')
                ->post(['json' => [
                    'mchid'        => self::$merchantId,
                    'out_trade_no' => $params['out_trade_no'],
                    'appid'        => self::$appid,
                    'description'  => $params['subject'],
                    'notify_url'   => $notify_url,
                    'amount'       => [
                        'total'    => round($params['total_amount'] * 100),
                        'currency' => 'CNY'
                    ],
                    'scene_info'   => [
                        'payer_client_ip' => get_client_ip(), // 【用户终端IP】 用户的客户端IP，支持IPv4和IPv6两种格式的IP地址。
                        'h5_info'  => [
                            'type' => 'Wap' // 【场景类型】 场景类型，使用H5支付的场景：Wap、iOS、Android
                        ],
                    ],
                ]]);



            if ($resp->getStatusCode() === 200) {
                $result = json_decode($resp->getBody(), true);
                return [
                    'code' => 1,
                    'msg' => 'success',
                    'order_no' => $params['out_trade_no'],
                    'data' => [
//                        'pay_url' => $result['h5_url'].'&redirect_url='.$params['quit_url']
                        'pay_url' => $result['h5_url']
                    ]
                ];
            } else {
                return [
                    'code' => 0,
                    'msg' => '支付请求失败'
                ];
            }

        } catch (Exception $e) {
            Log::error('微信H5支付异常：' . exception_info($e));
            return [
                'code' => 0,
                'msg' => $e->getMessage()
            ];
        }
    }

    /**
     * 微信H5支付
     * @param array $params 支付参数
     * @return array
     */
    public static function jsapiPay($params, $notify_url)
    {
        try {
            // 初始化配置
            self::initConfig();
            // 初始化客户端
            $array = [
                'mchid'      => self::$merchantId,
                'serial'     => self::$merchantSerialNumber,
                'privateKey' => self::$merchantPrivateKey,
                'certs'      => [
                    self::$platformCertificateSerial => self::$platformPublicKeyInstance,
                ],
            ];
            $instance = Builder::factory($array);
            // 以 Native 支付为例，发送请求
            $resp = $instance
                ->chain('v3/pay/transactions/jsapi')->post(['json' => [
                    'appid'        => self::$appid,
                    'mchid'        => self::$merchantId,
                    'description'  => $params['subject'],
                    'out_trade_no' => $params['out_trade_no'],
                    'notify_url'   => $notify_url,
                    'amount'       => [
                        'total'    => round($params['total_amount'] * 100),
                        'currency' => 'CNY'
                    ],
                    'payer'=>[
                        'openid' => $params['openid'],
                    ],
                    'scene_info'   => [
                        'payer_client_ip' => get_client_ip(), // 【用户终端IP】 用户的客户端IP，支持IPv4和IPv6两种格式的IP地址。
                    ],
                ]]);
            if ($resp->getStatusCode() === 200) {
                $result = json_decode($resp->getBody(), true);
                // 准备待签名字符串
                $timeStamp = (string) time();
                $nonceStr = Formatter::nonce();
                $package = 'prepay_id='.$result['prepay_id'];
//                dump(Formatter::joinedByLineFeed(self::$appid,$timeStamp,$nonceStr,$package));
                return [
                    'code' => 1,
                    'msg' => 'success',
                    'order_no' => $params['out_trade_no'],
                    'data' => [
                        'appId' => self::$appid,
                        'timeStamp' => $timeStamp,
                        'nonceStr' => $nonceStr,
                        'package' => 'prepay_id='.$result['prepay_id'],
                        'signType' => 'RSA',
                        'paySign' => Rsa::sign(Formatter::joinedByLineFeed(self::$appid,$timeStamp,$nonceStr,$package),
                            self::$merchantPrivateKey),
                    ]
                ];
            } else {
                return [
                    'code' => 0,
                    'msg' => '支付请求失败'
                ];
            }

        } catch (Exception $e) {
            Log::error('微信支付异常：' . exception_info($e));
            return [
                'code' => 0,
                'msg' => $e->getMessage()
            ];
        }
    }


    /**
     * 微信订单查询
     */
    public static function query($out_trade_no)
    {
        try {
            // 初始化配置
            self::initConfig();
            // 初始化客户端
            $array = [
                'mchid'      => self::$merchantId,
                'serial'     => self::$merchantSerialNumber,
                'privateKey' => self::$merchantPrivateKey,
                'certs'      => [
                    self::$platformCertificateSerial => self::$platformPublicKeyInstance,
                ],
            ];

            $instance = Builder::factory($array);
            // 正确的请求方式 - 使用数组参数
            $response = $instance->chain('v3/pay/transactions/out-trade-no/{out_trade_no}')->get([
                'out_trade_no' => $out_trade_no,
                'query' => [
                    'mchid' => self::$merchantId,
                ],
            ]);


            if ($response->getStatusCode() === 200) {
                $result = json_decode($response->getBody(), true);

                return [
                    'code' => 1,
                    'msg' => 'success',
                    'data' => self::getTradeStateDesc($result['trade_state']),
                ];
            } else {
                return [
                    'code' => 0,
                    'msg' => '支付请求失败'
                ];
            }

        } catch (Exception $e) {
            Log::error('微信H5支付查询异常：' . exception_info($e));
            return [
                'code' => 0,
                'msg' => $e->getMessage()
            ];
        }
    }

    /**
     * 获取交易状态描述
     */
    private static function getTradeStateDesc($state)
    {
        $states = [
            'SUCCESS' => 1,
            'REFUND' => 1,
            'NOTPAY' => 0,
            'CLOSED' => 1,
            'REVOKED' => 1,
            'USERPAYING' => 0,
            'PAYERROR' => 1,
        ];

        return $states[$state] ?? 0;
    }

    /**
     * 验证解密微信支付回调
     */
    public static function verifyNotify($body, $headers) {
        Log::info('微信支付异步通知Header：' . json_encode($headers));
        self::initConfig();
        $inWechatpaySignature = $headers['wechatpay-signature'];// 请根据实际情况获取
        $inWechatpayTimestamp = $headers['wechatpay-timestamp'];// 请根据实际情况获取
        $inWechatpaySerial = $headers['wechatpay-serial'];// 请根据实际情况获取
        $inWechatpayNonce = $headers['wechatpay-nonce'];// 请根据实际情况获取

        // 检查通知时间偏移量，允许5分钟之内的偏移
        $timeOffsetStatus = 300 >= abs(Formatter::timestamp() - (int)$inWechatpayTimestamp);
        $verifiedStatus = Rsa::verify(
            Formatter::joinedByLineFeed($inWechatpayTimestamp, $inWechatpayNonce, $body), 
            $inWechatpaySignature, 
            self::$platformPublicKeyInstance
        );
        if($timeOffsetStatus && $verifiedStatus) {
            $inBodyArray = (array)json_decode($body, true);
            ['resource' => [
                'ciphertext'      => $ciphertext,
                'nonce'           => $nonce,
                'associated_data' => $aad
            ]] = $inBodyArray;
            $inBodyResource  = AesGcm::decrypt($ciphertext, self::$api_v3_key, $nonce, $aad);
            return (array)json_decode($inBodyResource, true);
        }
        return [];
    }
}
